package com.javasm.boot.oauth2.aop;

import com.javasm.boot.oauth2.entity.MyAuthentication;
import com.javasm.boot.oauth2.entity.Perm;
import lombok.AllArgsConstructor;
import org.apache.http.util.Asserts;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Author：MoDebing
 * Version：1.0
 * Date：2022-12-20-15:29
 * Description:
 */
@Aspect
@AllArgsConstructor
@Component
public class PermissionAop {

    private TokenStore tokenStore;

    @Pointcut("@annotation(com.javasm.boot.oauth2.entity.Perm)")
    public void method(){}

    @Before("method()")
    public void handler(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        MyAuthentication[] annotation = signature.getMethod().getAnnotation(Perm.class).value();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Asserts.notNull(attributes,"当前请求");
        HttpServletRequest request = attributes.getRequest();
        List<String> pathPermission = Arrays.stream(annotation).map(MyAuthentication::getPermission).collect(Collectors.toList());
        // 解析token,查看用户是否有权限访问该路径
        String bearer = request.getHeader("Authorization");
        if (StringUtils.hasText(bearer) && bearer.contains("Bearer")){
            String token = bearer.split("Bearer ")[1];
            OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(token);
            Authentication userAuthentication = oAuth2Authentication.getUserAuthentication();
            // 用户的权限
            List<String> authorities = userAuthentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(authorities)|| authorities.stream().noneMatch(pathPermission::contains)){
                throw new AccessDeniedException("无权限");
            }
        }
    }
}
